/*
 * JaCoLiB
 * Copyright (C) 2008 Alessandro Serra
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package it.gashale.jacolib.connection.connector;

import it.gashale.jacolib.connection.Connection;
import it.gashale.jacolib.connection.auth.Authenticator;
import it.gashale.jacolib.core.JacolibError;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Logger;

public class ServerConnector extends Connector {
	private static Logger logger = Logger.getLogger("it.gashale.jacolib.connection.connector.ServerConnector");
	
	private boolean use_multi_thread;
	
	private Thread main_thread;
	private ServerSocket server;
	
	private ConnectionHandler connection_handler;
	
	public ServerConnector(int port, String secret, ConnectionHandler handler) throws JacolibError {
		super(port,secret,handler);
		use_multi_thread=false;
		main_thread=null;
		this.connection_handler=handler;
		try {
			logger.info("java server listening on port " + getPort()+" protected by the password: "+secret+".");
			server=new ServerSocket(getPort());
		} catch (IOException e) {
			throw new JacolibError(e.getMessage());
		}
	}
	public boolean getUseMultiThread() {
		return use_multi_thread;
	}
	public void setUseMultiThread(boolean v) {
		use_multi_thread=v;
	}
	public ConnectionHandler getConnectionHandler() {
		return connection_handler;
	}
	public void setConnectionHandler(ConnectionHandler s) {
		connection_handler=s;
	}
	/*
	 * 
	 */
	public void quit() throws JacolibError {
		try {
			logger.info("java server closed");
			server.close();
			server=null;
			if(use_multi_thread)
				main_thread.interrupt();
		} catch (IOException e) {
			throw new JacolibError(e.getMessage());
		}
	}
	public void run() throws JacolibError {
		if(use_multi_thread)
			main_thread=Thread.currentThread();
		for(int i=0; ;++i) {
			try {		
				if(server==null)
					return;
				Socket socket=server.accept();
				if(socket!=null) {
					ServerConnectorHandler handler=new ServerConnectorHandler(socket,i);
					if(use_multi_thread) {
						new Thread(handler).run();
					} else {
						handler.run();
					}
				} else {
					return;
				}
			} catch (IOException e) {
				throw new JacolibError(e.getMessage());
			}
		}
	}
	
	private class ServerConnectorHandler implements Runnable {
		protected Socket socket;
		protected int i;

		public ServerConnectorHandler(Socket socket, int i) {
			this.socket=socket;
			this.i=i;
		}
		
		public void run() {
			try {
				boolean hello=Authenticator.ask_authetication(socket,getAuthType(),getSecretString());
				if(hello) {
					logger.info("client connected");
					Connection con=new Connection(socket);
					getConnectionHandler().handle(con,i);
					logger.info("client disconnected");
				} else {
					logger.info("client authorization fails");
				}
			} catch(JacolibError e) {
				logger.finer("[connection-handler]: "+e.toString());
			} catch (IOException e) {
				logger.finer("[connection-handler]: "+e.toString());
			}
		}
	}
}
